package com.taomus.mytools.helper.xml;

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.util.ArrayList;
import java.util.List;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Node;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.taomus.mytools.helper.ObjectHelper;
import com.taomus.mytools.helper.StringHelper;
import com.taomus.mytools.helper.xml.annotations.Attribute;
import com.taomus.mytools.helper.xml.annotations.Element;

public class ToXmlMapping {
	final static Logger LOG = LoggerFactory.getLogger(ToXmlMapping.class);

	public String mapping(Object instance) throws Exception {
		Document document = DocumentHelper.createDocument(); 
		Class<?> cl = instance.getClass();
		Element rootElement = cl.getAnnotation(Element.class);
		org.dom4j.Element rootXmlElement = null;
		if(ObjectHelper.isNotNull(rootElement)){
			String nodeName = StringHelper.defaultIfEmpty(rootElement.value(),cl.getSimpleName().toLowerCase());
			rootXmlElement = DocumentHelper.createElement(nodeName);
			document.add(rootXmlElement);
		}else{
			throw new Exception("unknown xml root Element");
		}
		for (Field field : cl.getDeclaredFields()) {
			field.setAccessible(true);
			if(ObjectHelper.isNotNull(rootXmlElement)){
				addElement(instance,field,rootXmlElement);
			}
		}
		return document.asXML();
	}
	/**
	 * 向标签中添加元素
	 * @param instance
	 * @param field
	 * @param xmlElm
	 * @return
	 * @throws IllegalArgumentException
	 * @throws IllegalAccessException
	 */
	public Object addElement(Object instance, Field field,org.dom4j.Element xmlElm) throws IllegalArgumentException, IllegalAccessException {
		Element elm = field.getAnnotation(Element.class);
		Attribute attr = field.getAnnotation(Attribute.class);
		switch (field.getType().getName()) {
		case "java.lang.String":
		case "int":
		case "java.lang.Integer":
		case "short":
		case "java.lang.Short":
		case "long":
		case "java.lang.Log":
		case "float":
		case "java.lang.Float":
		case "double":
		case "java.lang.Double":
		case "char":
		case "java.lang.Character":
		case "boolean":
		case "java.lang.Boolean":
			if(ObjectHelper.isNotNull(elm)){
				String nodeName = StringHelper.defaultIfEmpty(elm.value(),field.getName().toLowerCase());
				org.dom4j.Element node = DocumentHelper.createElement(nodeName);
				node.addText(String.valueOf(field.get(instance)));
				xmlElm.add(node);
			}else if(ObjectHelper.isNotNull(attr)){
				String attrName = StringHelper.defaultIfEmpty(attr.value(),field.getName().toLowerCase());
				xmlElm.addAttribute(attrName,String.valueOf(field.get(instance)));
			}
			break;
		//循环结构数据
		case "java.util.List":
		case "java.util.ArrayList":
			listElement(instance,field,xmlElm);
			break;
		default:
			if(ObjectHelper.isNotNull(elm)){
				Object obj2 = field.get(instance);
				if(ObjectHelper.isNull(obj2)){
					break;
				}
				String nodeName = StringHelper.defaultIfEmpty(elm.value(),field.getName().toLowerCase());
				org.dom4j.Element node = DocumentHelper.createElement(nodeName);
				xmlElm.add(node);
				try {
					Class<?> cl = Thread.currentThread().getContextClassLoader().loadClass(field.getGenericType().getTypeName());
					for(Field field2 : cl.getDeclaredFields()){
						field2.setAccessible(true);
						addElement(obj2,field2,node);
					}
				} catch (ClassNotFoundException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			break;
		}

		return null;
	}
	
	/**
	 * 处理类中的list字段
	 * 
	 * @param doc
	 * @param instance
	 * @param field
	 * @param nodes
	 * @throws IllegalArgumentException
	 * @throws IllegalAccessException
	 */
	private void listElement(Object instance, Field field,org.dom4j.Element xmlElm)
			throws IllegalArgumentException, IllegalAccessException {
		ParameterizedType pt = (ParameterizedType) field.getGenericType();
		String typeName = pt.getActualTypeArguments()[0].getTypeName();
		Element elm = field.getAnnotation(Element.class);
		switch (typeName) {
		case "java.lang.String":
		case "java.lang.Integer":
		case "java.lang.Log":
		case "java.lang.Short":
		case "java.lang.Float":
		case "java.lang.Double":
		case "java.lang.Boolean":
			if(ObjectHelper.isNotNull(elm)){
				for(Object obj:(List<?>)field.get(instance)){
					String nodeName = StringHelper.defaultIfEmpty(elm.value(),field.getName().toLowerCase());
					xmlElm.addElement(nodeName);
					xmlElm.addText(String.valueOf(obj));
				}
			}
		break;
		default:
			try {
				Class<?> cl = Thread.currentThread().getContextClassLoader().loadClass(typeName);
				for (Object obj :(List<?>)field.get(instance)) {
					org.dom4j.Element newElement = null;
					if(ObjectHelper.isNotNull(elm)){
						String nodeName = StringHelper.defaultIfEmpty(elm.value(),field.getName().toLowerCase());
						newElement = xmlElm.addElement(nodeName);
					}
					for (Field field2 : cl.getDeclaredFields()) {
						field2.setAccessible(true);
						addElement(obj,field2,newElement);
					}
				}
			} catch (ClassNotFoundException e) {
				e.printStackTrace();
			}
			break;
		}
	}
}
